Skip to content

chore: add WordPress.com OAuth support to iOS and Android demo apps#339

Merged
dcalhoun merged 11 commits intotrunkfrom
jkmassel/wordpress-com-support
Mar 24, 2026
Merged

chore: add WordPress.com OAuth support to iOS and Android demo apps#339
dcalhoun merged 11 commits intotrunkfrom
jkmassel/wordpress-com-support

Conversation

@jkmassel
Copy link
Copy Markdown
Contributor

@jkmassel jkmassel commented Feb 25, 2026

What?

Add WordPress.com OAuth2 authentication support to both the Android and iOS demo apps, alongside the existing Application Passwords flow for self-hosted sites.

Why?

The demo apps previously only supported self-hosted WordPress sites via Application Passwords. This made testing WordPress.com sites an integration concerns in other apps, which means it's not getting tested as much as it needs to. This PR adds OAuth2 support so the apps can also connect to WordPress.com sites, and upgrades credential storage to use encrypted repositories on both platforms.

How?

Android

  • Branch on DiscoveredAuthenticationMechanism to launch the appropriate auth flow (Application Passwords or OAuth2)
  • Store WP.com accounts as Account.WpCom so auth type is determined by pattern matching
  • Replace SharedPreferences with encrypted AccountRepository from wordpress-rs, backed by Android Keystore
  • Add WP.com site namespace handling in SitePreparationViewModel

iOS

  • Add AuthenticationManager with async/throws API supporting both Application Passwords and OAuth2 flows
  • Replace UserDefaults-based ConfigurationStorage with encrypted AccountRepository from wordpress-rs (SecureEnclavePasswordTransformer)
  • Use WpComDotOrgApiUrlResolver for correct WP.com API URL routing
  • Propagate errors from ConfigurationStorage instead of swallowing them

Shared (JS/Web)

  • Replace fetch-based editor asset loading with config injection via window.GBKit.editorAssets. (We have the data already, so why download it again?)
  • Guard against duplicate site namespace insertion in the API path modifier middleware
  • Move shared WP.com OAuth credentials file to project root, referenced by both platforms

Testing Instructions

  1. Self-hosted (Android or iOS): Tap "Add WordPress site", enter a self-hosted site URL → Application Passwords flow → verify editor loads
  2. WordPress.com (Android or iOS): Copy wp_com_oauth_credentials.json.example to wp_com_oauth_credentials.json in the project root, fill in client_id/secret → enter a WP.com site URL → OAuth browser flow → verify editor loads with plugins and theme styles
  3. Verify sites persist across app restarts
  4. Verify site deletion works (iOS: swipe to delete, Android: long-press)
  5. In a WP.com site – try adding an AI block and asking it to make you a haiku. Do the same with a Jetpack site. This validates third-party plugin support and the ability for the editor to make authenticated requests to the remote site.
  6. In a self-hosted site (you can use vanilla.wpmt.co) load the editor and ensure that theme styles are loaded. This validates remote theme style loading.

🤖 Generated with Claude Code

@jkmassel jkmassel added the [Type] Enhancement A suggestion for improvement. label Feb 25, 2026
@jkmassel jkmassel force-pushed the jkmassel/wordpress-com-support branch from 5eeb6cc to 0b13e7f Compare February 25, 2026 21:12
@jkmassel jkmassel force-pushed the jkmassel/wordpress-com-support branch 2 times, most recently from 8681b6b to 6bc5e33 Compare February 25, 2026 22:36
@jkmassel jkmassel changed the title feat: Add WordPress.com OAuth support to Android demo app feat: Add WordPress.com OAuth support to iOS and Android demo apps Mar 18, 2026
@jkmassel jkmassel force-pushed the jkmassel/wordpress-com-support branch 4 times, most recently from 5d71872 to e601f8d Compare March 19, 2026 20:02
jkmassel and others added 4 commits March 19, 2026 14:30
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jkmassel jkmassel force-pushed the jkmassel/wordpress-com-support branch from e601f8d to 913043c Compare March 19, 2026 20:30
@jkmassel jkmassel requested a review from dcalhoun March 19, 2026 21:22
@jkmassel jkmassel marked this pull request as ready for review March 19, 2026 21:23
kotlinx-coroutines = '1.10.2'
androidx-recyclerview = '1.3.2'
wordpress-rs = 'trunk-d02efa6d4d56bc5b44dd2191e837163f9fa27095'
wordpress-rs = '1190-c2b404d9c9754b229967386fa7460d65fe87a29d'
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will need to be updated to a trunk revision prior to merging

Copy link
Copy Markdown
Member

@dcalhoun dcalhoun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation tested well for me. 🎉

Code looks good overall, but I left several inline notes we should address before merging.

*/
suspend fun fetchEditorSettings(): EditorSettings {
if (!configuration.themeStyles) {
if (!configuration.plugins && !configuration.themeStyles) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was explicitly removed in ba7c9c2, as it led to erroneous, error-producing requests for a non-existing endpoint. We should likely revert this unless there an explicit reason to reintroduce this.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #400.

Comment on lines +102 to +106
await expect(
page.getByText(
'Loading plugins failed, using default editor configuration.'
)
).toBeVisible( { timeout: 10_000 } );

// Editor should still be functional despite the plugin failure.
await expect(
page.locator( '.gutenberg-kit-visual-editor' )
).toBeVisible();
).toBeHidden();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a false-positive given it searches for something to be hidden. Did it ever render at all? If not and that is expected, we should merely remove this assertion.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #400.

const config = {
...DEFAULT_GBKIT,
editorSettings,
...( editorAssets && { editorAssets } ),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine this could be simplified to align with editorSettings.

Suggested change
...( editorAssets && { editorAssets } ),
editorAssets,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #400.

Toggle("Enable Native Inserter", isOn: $viewModel.enableNativeInserter)
Toggle("Enable Network Logging", isOn: $viewModel.enableNetworkLogging)

Picker("Network Fallback", selection: $viewModel.networkFallbackMode) {
Copy link
Copy Markdown
Member

@dcalhoun dcalhoun Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given removing this isn't referenced or explained in the PR description, I presume this was an erroneous merge conflict resolution. We should reinstate this change from f5c91cc that improves the offline editor experience.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #400.

import parseException from './exception-parser';
import { debug, error } from './logger';
import { isDevMode } from './dev-mode';
import { basicFetch } from './fetch';
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the only usage of basicFetch. We should remove that module entirely.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #400.

Comment on lines -197 to -198
src/translations/*
!src/translations/.gitkeep
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presuming this is a bad merge conflict resolution. We should reinstate this change from 3079431. This ensures the translations directory always exists to avoid Node.js module load errors.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #400.

.wp-env.credentials.json
wp-env/mu-plugins/*
!wp-env/mu-plugins/gutenbergkit-cors.php
!wp-env/mu-plugins/gutenbergkit-jetpack-blocks.php
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presuming this is a bad merge conflict resolution. We should reinstate this change from aa8eaf1. It ensure our custom MU plugin is tracked, while others are excluded.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #400.

Copy link
Copy Markdown
Member

@dcalhoun dcalhoun Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add project documentation linking to relevant documentation for creating WordPress.com Apps for OAuth and noting the required Redirect URL value.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #400.

dcalhoun and others added 7 commits March 24, 2026 10:35
* chore: ensure OAuth credentials are copied before assets are merged on Android

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: restore translation files .gitignore pattern

Restore the gitignore pattern from 3079431 that was lost during merge
conflict resolution. This ensures the translations directory always
exists (via .gitkeep) to avoid Node.js module load errors.

Ref: 3079431

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: restore wp-env mu-plugin .gitignore exception

Restore the gitignore exception from aa8eaf1 that was lost during merge
conflict resolution. This ensures the custom Jetpack blocks MU plugin
is tracked while other MU plugins are excluded.

Ref: aa8eaf1

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: restore editor settings guard condition

Restore the guard from ba7c9c2 that was lost during merge conflict
resolution. The guard should check only `themeStyles`, not both
`plugins` and `themeStyles`, to avoid 404s on sites that support
plugins but not the editor settings endpoint.

Ref: ba7c9c2

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: restore network fallback picker and offline handling

Restore the Network Fallback picker UI, networkFallbackMode property,
offline error handling, and buildOfflineConfiguration helper that were
lost during merge conflict resolution. Adapted from ConfiguredEditor
to Account type to match the current branch's data model.

Ref: f5c91cc

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: simplify editorAssets config in E2E helper

Align editorAssets with editorSettings by using a plain property
instead of a conditional spread.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: remove false-positive toBeHidden assertion in E2E test

The toBeHidden() assertion passes vacuously because the plugin load
failure notice never renders when plugins are enabled without
editorAssets — loadEditorAssets() returns {} without error, so
pluginLoadFailed is false. The toBeVisible() check for the editor
already confirms successful load.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: remove unused basicFetch module

The basicFetch export in src/utils/fetch.js has no remaining importers
after the bridge was updated to use native communication instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add WordPress.com OAuth setup documentation

Add documentation for creating a WordPress.com application for OAuth
and configuring the demo apps with the required credentials, including
the required Redirect URL value.

Ref: https://developer.wordpress.com/docs/api/oauth2/

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* build: update wordpress-rs to trunk revision

Update from branch revision (1190-c2b404d) to trunk revision
(dc86c7a) as required before merging.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* task: Use latest WpApiError type

The outdated structure led to build errors after updating the
wordpress-rs revision.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…om-support

# Conflicts:
#	android/app/src/main/java/com/example/gutenbergkit/AuthenticationManager.kt
#	android/app/src/main/java/com/example/gutenbergkit/ConfigurationItem.kt
#	android/app/src/main/java/com/example/gutenbergkit/ConfigurationStorage.kt
Adapt to breaking changes in wordpress-rs (dc86c7a6):
- WpLoginClient and WpComApiClient now require NetworkAvailabilityProvider
- KeystorePasswordTransformer now requires applicationName parameter

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Resolves Kotlin compiler warnings about accessing the transitive
Interceptor class from wordpress-rs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The OAuth changes in AuthenticationManager.kt and MainActivity.kt
altered function signatures that no longer matched the baseline
entries introduced by the Detekt PR in trunk.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the single NetworkAvailabilityProvider instance to
GutenbergKitApplication, matching the existing pattern used
for AccountRepository.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Only register the copyOAuthCredentials task and asset source directory
when wp_com_oauth_credentials.json exists. This avoids a Gradle task
dependency validation error in CI where the file is absent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Member

@dcalhoun dcalhoun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The latest iteration tested well for me on both iOS and Android. 🎉

All feedback/issues were addressed in #400 or subsequent commits.

@dcalhoun dcalhoun changed the title feat: Add WordPress.com OAuth support to iOS and Android demo apps chore: add WordPress.com OAuth support to iOS and Android demo apps Mar 24, 2026
@dcalhoun dcalhoun removed the [Type] Enhancement A suggestion for improvement. label Mar 24, 2026
@dcalhoun dcalhoun added the [Type] Task Issues or PRs that have been broken down into an individual action to take label Mar 24, 2026
@dcalhoun dcalhoun merged commit 8193734 into trunk Mar 24, 2026
16 checks passed
@dcalhoun dcalhoun deleted the jkmassel/wordpress-com-support branch March 24, 2026 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Type] Task Issues or PRs that have been broken down into an individual action to take

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants